/*
 * <one line to give the program's name and a brief idea of what it does.>
 * Copyright (C) 2019
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef PLAYER_H
#define PLAYER_H

#include "commondata.hpp"

#include <nlohmann/json_fwd.hpp>
#include <condition_variable>
#include <atomic>
#include <mutex>

class Arena;
class DataBase;
class DBLMDB;
class DBSQLite;

struct PathWorketMT {
	DataBase * queue;
	DataBase * out;
	std::condition_variable * ready;
	std::mutex * mutex;
};

/**
 * \class Player
 * This class use for manipulate with player data
 * Searchg path, search limit, import, export data
 */
class Player {
public:
	Player() = delete;
	Player(const Player & other) = delete;

	/**
	 * Import player data from file
	 * Test build and test AI level are limits for searching
	 * \param[in] file file for import
	 * \param[in,out] data file for export
	 */
	static bool importData(const char * file, PlayerData * data);

	/**
	 * Export player data to file
	 * Use then search complete and path was finded
	 * \param[in] file file to export
	 * \param[in] data player data
	 */
	static bool exportData(const char * file, const PlayerData * data);

	/**
	 * Check JSON data
	 * \param[in] data pointer to json object
	 * \return true if this json valid, false if not
	 */
	static bool checkJSON(const nlohmann::json & data);

	/**
	 * Create tops for graph and put them to out Database
	 * \param[out] out pointer to DataBase, where we store our graph
	 * \param[in] data player data
	 */
	static void createGraph(DataBase * out, PlayerData data);

	/**
	 * Create graph in multi thread mode
	 * Split all variants by N sectors, create N thread, one for sector
	 * \param[out] out pointer to DataBase, where we store our graph
	 * \param[in] data player data
	 */
	static void createGraphMT(DataBase * out, PlayerData data);

	/**
	 * get sector id
	 * \param[in] data build data
	 * \param[in] maxID total amount of sectors
	 */
	static uint16_t sectorID(const PlayerBuild * data, const uint16_t maxID);

	/**
	 * \param[in,out] workerData vector with data for all workers
	 * \param[in] data player data
	 * \param[in] stop max AI level when must stop
	 * \param[in] maxID total amount of sectors
	 */
	static void graphWorkerMT(std::vector<PathWorketMT> * workerData,
	                          PlayerData data,
	                          std::atomic<bool> & stop,
	                          uint16_t workerID,
	                          uint16_t maxID);

	/**
	 * Worker for creating graph. can be use in mt mode
	 * \param[out] queue Database for generated builds
	 * \param[in,out] out Database for store calculated builds and checks
	 * \param[in] data player data
	 */
	static void graphWorker(DataBase * queue, DataBase * out, PlayerData data);

	/**
	 * create full path for each level
	 * \param[in] db SQLite database with graph
	 * \param[in] data player data
	 */
	static void finalizePath(DataBase *db, PlayerData data);

	/**
	 * Check if player can win with this build
	 * \param[in] fight Arena for battle simulation
	 * \param[in] data player data
	 */
	static bool checkWin(Arena * fight, PlayerData * data);

private:
	/**
	 * Convert drone type to name, using in export
	 * \param[in] type drone type
	 * \return drone name
	 */
	static std::string droneTypeToName(const droneType type);

	/**
	 * Convert drone name to type, using in import
	 * \param[in] name drone name
	 * \return drone type
	 */
	static droneType droneNameToType(const std::string name);

	static std::mutex m_Mutex;
};

#endif
